package com.glodon.springbootredission.aop;

import com.glodon.springbootredission.annotation.RedissonLockAnnotation;
import com.glodon.springbootredission.util.RedissonLockUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;

/**
 * @author zhaoxin
 * @version 1.0
 * @description: 分布式锁/防重复提交 aop
 * @date 2021/11/12 15:11
 */
@Aspect
@Component
@Slf4j
public class RedissonLockAop {
    @Pointcut("@annotation(com.glodon.springbootredission.annotation.RedissonLockAnnotation)" +
            "||@within(com.glodon.springbootredission.annotation.RedissonLockAnnotation)")
    public void redissionPointCut() {
    }
    @Around("redissionPointCut()")
    public Object checkLock(ProceedingJoinPoint joinPoint) throws Throwable {
        //当前线程名
        String threadName = Thread.currentThread().getName();
        log.info("线程{}------进入分布式锁aop------", threadName);
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        RedissonLockAnnotation annotation = signature.getMethod().getAnnotation(RedissonLockAnnotation.class);

        StringBuffer keyBuffer = new StringBuffer();
        Object[] args = joinPoint.getArgs();
        for (int i = 0; i < args.length; i++) {
            keyBuffer.append(args[i]);
        }


        String key = keyBuffer.toString();
            log.info("线程{} 要加锁的key={}", threadName, key);

            //获取锁
            if (RedissonLockUtils.tryLock(key, 3, 5, TimeUnit.SECONDS)) {
                try {
                    log.info("线程{} 获取锁成功", threadName);
                 return     joinPoint.proceed();
                } finally {
                    // 这里判断下当前key是否上锁，不然业务执行时间大于锁自动释放时间后，解锁报异常
                    if(RedissonLockUtils.isLock(key)){
                        //重复提交就不需要释放锁,waitTime 改小
                       // RedissonLockUtils.unlock(key);
                        log.info("线程{} 释放锁", threadName);
                    }
                }
            } else {
                log.info("线程{} 获取锁失败", threadName);
                return "系统繁忙，请稍后再试";
            }

        }



}
